package com.arajuuri.catinvaders;

import com.arajuuri.catinvaders.fileoperations.Images;
import com.arajuuri.catinvaders.fileoperations.Objects;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.DisplayMode;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.MemoryImageSource;
import java.util.Collections;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.JFrame;


/**
 * <p>Title: Cat Invaders</p>
 * <p>Description: A space invaders clone with cats</p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: </p>
 * @author Semi Arajuuri
 * @version 1.0
 */

public class GameWindow extends JFrame {
  private Vector goVector;
  private Vector highScoreVector=new Vector();
  private Human human = new Human(this);
  private boolean menu = true;
  private int speed;
  private int gravity;
  private int cats;
  private Image newGame[] = new Image[2];
  private Image exit[] = new Image[2];
  private Image highscores[] = new Image[2];
  private Image background;
  private Image menubackground;
  private Image gameover;
  private GraphicsDevice gs;
  private DisplayMode dm;
  private Graphics2D g2d;
  private BufferStrategy bs;
  private boolean allHidden=false;
  private boolean gameOver=false;
  private boolean inputHighScore=false;
  private boolean showHighScores=false;
  private boolean paused=false;
  private int selected[] = {1, 0, 0};
  private AnimationThread anim=new AnimationThread();
  private StringBuffer highScore=new StringBuffer();
  private final Font gameFont=new Font("Monospaced", Font.BOLD, 40);
  private FontMetrics fontMetrics;
  private Images images = new Images();

  public GameWindow() {
    initGame();
    newGame[0] = images.loadImage("newgame1.png");
    newGame[1] = images.loadImage("newgame2.png");
    exit[0] = images.loadImage("exit1.png");
    exit[1] = images.loadImage("exit2.png");
    highscores[0] = images.loadImage("highscores1.png");
    highscores[1] = images.loadImage("highscores2.png");
    background = images.loadImage("background.png");
    menubackground = images.loadImage("menubg.png");
    gameover = images.loadImage("gameover.png");
    Object obj=Objects.readObjectFromFile("highscores.bin");
    if(obj instanceof Vector){
      highScoreVector=(Vector)obj;
    }
    Toolkit tk = Toolkit.getDefaultToolkit();
    Image image = tk.createImage(new MemoryImageSource(16, 16, new int[16 * 16],
        0, 16));
    Cursor transparentCursor = tk.createCustomCursor(image, new Point(0, 0),
        "invisiblecursor");
    setUndecorated(true);
    setIgnoreRepaint(true);
    setCursor(transparentCursor);
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    gs = ge.getDefaultScreenDevice();
    dm = gs.getDisplayMode();
    addKeyListener(new keyListener());
    gs.setFullScreenWindow(this);
    gs.setDisplayMode(new DisplayMode(800, 600, dm.getBitDepth(),
                                      dm.getRefreshRate()));
    createBufferStrategy(2);
    bs = getBufferStrategy();
    anim.start();
    show();
  }

  private class AnimationThread extends Thread {
    long delay;
    final int fps=30;

    public AnimationThread(){
      delay=1000/30;
    }

    public void run(){
      boolean done=false;
      long tm = System.currentTimeMillis();
      while (!done) {
        if(!paused){
          render();
          try {
            tm+=delay;
            sleep(Math.max(0, tm-System.currentTimeMillis()));
          }
          catch (InterruptedException ie) {}
        }
      }
    }
  }

  public Vector getGraphicalObjects(){
    return goVector;
  }

  public void newLevel(int cats, int speed, int gravity){
    int x;
    CatLine line1,line2,line3;
    goVector=new Vector();
    goVector.add(human);
    line1=new CatLine(30, speed, gravity);
    line2=new CatLine(100, -speed, gravity);
    line3=new CatLine(180, speed, gravity);
    for(x=1;x<cats;x++){
     line1.addCat(new Cat("misu.png"));
     line2.addCat(new Cat("leevi.png"));
     line3.addCat(new Cat("viivi.png"));
   }
   goVector.add(line1);
   goVector.add(line2);
   goVector.add(line3);
   human.resetBullets();
 }

 public void initGame(){
   int x;
   int vSpace=60;
   human = new Human(this);
   speed=4;
   gravity=2;
   cats=8;
   gameOver=false;
   inputHighScore=false;
   newLevel(cats, speed, gravity);
 }

 public void renderMenu(Graphics2D g2d){
   int x[]=new int[3];
   int y[]=new int[3];
   x[0] = 400 - newGame[0].getWidth(null) / 2;
   x[1] = 400 - highscores[0].getWidth(null) / 2;
   x[2] = 400 - exit[0].getWidth(null) / 2;
   y[0] = 300 -
       (newGame[0].getHeight(null) + exit[0].getHeight(null) + 10) / 2;
   y[1] = y[0] + newGame[0].getHeight(null) + 10;
   y[2] = y[1] + highscores[0].getHeight(null) + 10;
   g2d.drawImage(menubackground, 0, 0, null);
   g2d.drawImage(newGame[selected[0]], x[0], y[0], null);
   g2d.drawImage(highscores[selected[1]], x[1], y[1], null);
   g2d.drawImage(exit[selected[2]], x[2], y[2], null);
 }

 public void renderEnterName(Graphics2D g2d){
   String top10="YOU ARE IN THE TOP 10!";
   String enterName="ENTER YOUR NAME:";
   int textWidth=fontMetrics.stringWidth(top10);
   g2d.setColor(Color.WHITE);
   g2d.fillRect(390-textWidth/2, 350, textWidth+20, 170);
   g2d.setColor(Color.BLACK);
   g2d.drawRect(390-textWidth/2, 350, textWidth+20, 170);
   g2d.drawString(top10, 400-fontMetrics.stringWidth(top10)/2, 400);
   g2d.drawString(enterName, 400-fontMetrics.stringWidth(enterName)/2, 450);
   g2d.drawString(highScore.toString(), 400-fontMetrics.stringWidth(highScore.toString())/2, 500);
 }

 public void renderHighScores(Graphics2D g2d){
   int y=0;
   Iterator highScoreIterator = highScoreVector.iterator();
   g2d.setColor(Color.BLACK);
   g2d.fillRect(0,0,800,600);
   g2d.drawImage(highscores[0], 400-highscores[0].getWidth(null)/2, highscores[0].getHeight(null), null);
   while(highScoreIterator.hasNext() && y < 10){
     HighScoreRow hsrow=(HighScoreRow)highScoreIterator.next();
     g2d.setColor(Color.WHITE);
     g2d.drawString(hsrow.getName(), 50, 120+y*50);
     String pointsString=Integer.toString(hsrow.getPoints());
     g2d.drawString(pointsString, 800-50-fontMetrics.stringWidth(pointsString), 120+y*50);
     y++;
   }
 }

 public void renderGame(Graphics2D g2d){
   int x, y;
   g2d.drawImage(background, 0, 0, null);
   allHidden=true;
   if(!gameOver){
     Iterator goIterator = goVector.iterator();
     while (goIterator.hasNext()) {
       GraphicalObject go = (GraphicalObject) goIterator.next();
       go.move();
       go.draw(g2d);
       if (!go.isHidden()) {
         allHidden = false;
       }
       if (go.getY()+go.getHeight() > human.getY() && !go.isHidden()) {
         gameOver = true;
         if(highScoreVector.size()>0){
           if ( ( (HighScoreRow) highScoreVector.lastElement()).getPoints() <
                human.getPoints() || highScoreVector.size() < 10) {
             inputHighScore = true;
           }
         }
         else{
           inputHighScore=true;
         }
       }
     }
   }
   else{
     x=400-gameover.getWidth(null)/2;
     y=300-gameover.getHeight(null)/2;
     g2d.drawImage(gameover, x, y, null);
     if(inputHighScore){
       renderEnterName(g2d);
     }
   }
   if (allHidden) {
     speed += 2;
     gravity += 1;
     newLevel(cats, speed, gravity);
   }
   g2d.setColor(Color.WHITE);
   g2d.drawString(Integer.toString(human.getPoints()), 800-fontMetrics.stringWidth(Integer.toString(human.getPoints())), 30);
 }

 public void render(){
   g2d = (Graphics2D)bs.getDrawGraphics();
   g2d.setFont(gameFont);
   fontMetrics=g2d.getFontMetrics();
   if (menu) {
     renderMenu(g2d);
   }
   else if (showHighScores) {
     renderHighScores(g2d);
   }
   else {
     renderGame(g2d);
   }
   bs.show();
   g2d.dispose();
 }

 public void exit(){
   gs.setDisplayMode(dm);
   gs.setFullScreenWindow(null);
   System.exit(0);
 }

  private class keyListener extends KeyAdapter implements KeyListener {
    public void keyPressed(KeyEvent e){
      int key=e.getKeyCode();
      if (key == KeyEvent.VK_ESCAPE && menu){
        exit();
      }
      else if (key == KeyEvent.VK_DOWN && menu){
        if(selected[0]==1){
          selected[0]=0;
          selected[1]=1;
        }
        else if(selected[1]==1){
          selected[1]=0;
          selected[2]=1;
        }
        else if(selected[2]==1){
          selected[2]=0;
          selected[0]=1;
        }
      }
      else if (key == KeyEvent.VK_UP && menu){
        if(selected[0]==1){
          selected[0]=0;
          selected[2]=1;
        }
        else if(selected[1]==1){
          selected[1]=0;
          selected[0]=1;
        }
        else if(selected[2]==1){
          selected[2]=0;
          selected[1]=1;
        }

      }
      else if (key == KeyEvent.VK_ESCAPE){
        menu=true;
        showHighScores=false;
      }
      else if (key == KeyEvent.VK_S && menu){
        if(selected[0]==1){
          initGame();
          menu=false;
          showHighScores=false;
        }
        else if (selected[1]==1){
          menu=false;
          showHighScores=true;
        }
        else if (selected[2]==1){
          exit();
        }
      }
      else if (!menu && !inputHighScore && !showHighScores)
      {
        if(key == KeyEvent.VK_P){
          paused=!paused;
        }
        else{
          human.keyPressEvent(e);
        }
      }
      else if (inputHighScore){
        if(key == KeyEvent.VK_BACK_SPACE){
          if(highScore.length()>0){
            highScore.delete(highScore.length() - 1, highScore.length());
          }
        }
        else if(key == KeyEvent.VK_ENTER && inputHighScore){
          highScoreVector.add(new HighScoreRow(highScore.toString(), human.getPoints()));
          Collections.sort(highScoreVector);
          if(highScoreVector.size()>10){
            highScoreVector.remove(10);
          }
          Objects.writeObjectToFile(highScoreVector, "highscores.bin");
          inputHighScore=false;
          menu=false;
          showHighScores=true;
        }
        else{
          highScore.append(e.getKeyChar());
        }
      }
    }

    public void keyReleased(KeyEvent e){
      if(!menu){
        human.keyReleaseEvent(e);
      }
    }
  }
}
